//
// Created by 吴喆 on 2020/3/18.
//

#include <sstream>
#include <map>
#include "Map.h"
#include "../util/Console.h"

const std::string Map::blank = "x";

Map::Map(Scene *scene, World *world) : scene(scene), world(world) {

}

Map::~Map() {
    for (auto floor : floors) {
        delete floor;
    }
}

void Map::render() {
    for (auto floor : floors) {
        floor->render();
    }
}

void Map::update() {
    for (auto floor : floors) {
        floor->update();
    }
}

/**
 * 加载map文件
 * @param file 文件路径
 * @description
 * 地图中每个单元为1*1的正方形
 * .map文件格式：
 *
 * ------head----------------------------
 * 0:tile.Overworld Tiles 8x_010.png
 * 1:tile.Overworld Tiles 8x_011.png
 * 2:tile.Overworld Tiles 8x_012.png
 * （blank line）
 * x               x               x             x             x             x             x
 * 5               9               5             x             x             5            10
 * 1(1,1)  0(1,1)[1]              11[2]             5             9            12|9|            12
 * x               x    3(0,0.5)[1]!      4(0.5,1)        0(1,1)        1(1,1)        0(1,1)
 * ------tail----------------------------
 *
 * "blank line"用于区分纹理编号与地图内容
 * "x"表示空气，不添加正方形纹理
 * 第一行表示地图最底下内容，第二行表示地图倒数第二行内容，以此类推；
 * "1(1,1)[1]!|12|4|"表示：
 * 该单位有三个纹理，编号为1，12，4（顺序为渲染顺序）
 * 该正方形用1号纹理"tile.Overworld Tiles 8x_011.png";
 * box2d的polyline相对与该正方形的坐标为"（0,1）(1,1)(左下角为（0,0）)";
 * !表示为底部，角色无法下跳;
 * [1][1,0]表示水平翻转纹理; [0,1]表示垂直翻转纹理; [1,1]表示水平垂直翻转纹理;
 */
void Map::loadMap(const char *file) {
    std::ifstream mapFile(file);
    if (!mapFile) {
        std::string info = "can not load file:";
        info.append(file);
        Console::ERR(info);
        return;
    }
    std::string line;
    bool flag = false;
    std::map<int, std::string> tileMap;
    std::string n;
    std::vector<std::vector<std::string>> mapVec;
    try {
        while (std::getline(mapFile, line)) {
            // BlankLine检测
            if (line.empty()) {
                flag = true;
                continue;
            }
            // 遍历纹理
            if (!flag) {
                int splitIndex = line.find_first_of(':');
                int num = std::stoi(std::string(line, 0, splitIndex));
                std::string textureId = std::string(line, splitIndex + 1, line.size() - splitIndex - 1);
                tileMap[num] = textureId;
            } else { // 解析地图
                std::istringstream sStream(line);
                std::vector<std::string> rowData;
                while (sStream >> n) {
                    rowData.push_back(n);
                }
                mapVec.push_back(rowData);
            }
        }
        mapFile.close();
        genFloor(mapVec, tileMap);
    } catch (std::exception &) {
        std::string info = ".map file format error!";
        info.append(file);
        Console::ERR(info);
    }

}

// 还不如用fori呢。。
void Map::genFloor(const std::vector<std::vector<std::string>> &mapVec, std::map<int, std::string> &tileMap) {
    int rowNum = 0;
    for (auto row : mapVec) {
        for (int n = 0; n < row.size(); n++) {
            auto sItr = row[n].begin();
            auto orItr = std::find(sItr, row[n].end(), '|');

            do {
                if (std::equal(blank.begin(), blank.end(), sItr)) {
                    continue;
                }
                bool isBottom = false;
                int vFlip = 0;
                int hFlip = 0;
                if (row[n][row[n].size() - 1] == '!') {
                    isBottom = true;
                }
                // 翻转判断
                auto squareBracketStartItr = std::find(sItr, orItr, '[');
                if (squareBracketStartItr != orItr) {
                    auto squareBracketEndItr = std::find(squareBracketStartItr, orItr, ']');
                    std::string tempFlip = std::string(squareBracketStartItr + 1, squareBracketEndItr);
                    auto splitItr = std::find(squareBracketStartItr, squareBracketEndItr, ',');
                    hFlip = std::stoi(std::string(squareBracketStartItr + 1, splitItr));
                    if (splitItr != squareBracketEndItr) {
                        vFlip = std::stoi(std::string(splitItr + 1, squareBracketEndItr));
                    }
                }

                auto startItr = std::find(sItr, orItr, '(');
                if (startItr == orItr) { // 没有线
                    int tileNum = std::stoi(std::string(sItr, orItr));
                    auto *floor = new Floor(scene, rowNum, n, tileMap[tileNum], hFlip == 1, vFlip == 1);
                    floors.push_back(floor);
                } else {
                    int tileNum = std::stoi(std::string(sItr, startItr));
                    auto endItr = std::find(startItr, orItr, ')');
                    std::string kv(startItr + 1, endItr);
                    auto splitItr = std::find(kv.begin(), kv.end(), ',');
                    float ry1 = std::stof(std::string(kv.begin(), splitItr));
                    float ry2 = std::stof(std::string(splitItr + 1, kv.end()));

                    Floor *floor;
                    floor = new Floor(scene, rowNum, n, tileMap[tileNum], ry1, ry2, world, isBottom, hFlip == 1, vFlip == 1);
                    floors.push_back(floor);
                }
                if (orItr != row[n].end()) {
                    sItr = orItr + 1;
                    orItr = std::find(orItr + 1, row[n].end(), '|');
                }
            } while (orItr != row[n].end());
        }
        rowNum++;
    }
}
